<?php

namespace baofu;


use baofu\SecurityUtil\AESUtil;
use baofu\SecurityUtil\RSAUtil;
use baofu\SecurityUtil\SignatureUtils;
use baofu\SecurityUtil\SHA1Util;
use baofu\Util\Log;
use baofu\Util\HttpClient;
use baofu\Util\Tools;
use think\Exception;

/**
 * 支付
 * @package baofu
 *
 *
 */
class Pay
{

    public $Version = "4.0.0.0";//版本号
    public $Member_Id = "100029078";    //商户号
    public $Terminal_Id = "200004282";    //终端号

    public $KEY_PWD = "123456";    //商户私钥证书密码

    public $KeyFolder = EXTEND_PATH . '/baofu/CerFile/';    //证书路径
    public $PFX_FILE_PATH = "bfkey_100029078@@200004282.pfx";  //注意证书路径是否存在
    public $CER_FILE_PATH = "bfkey_100029078@@200004282.cer";//注意证书路径是否存在

    public $POST_URL = "https://vgw.baofoo.com/cutpayment/protocol/backTransRequest";  //测试环境请求地址

    public $AesKey = '4f66405c4f66405c'; //商户自定义（可随机生成  商户自定义(AES key长度为=16位)）

    public $GLOBALS = [];

    public function __construct($config = [])
    {
        $this->PFX_FILE_PATH = $this->KeyFolder . $this->PFX_FILE_PATH;
        $this->CER_FILE_PATH = $this->KeyFolder . $this->CER_FILE_PATH;

        if(!empty($config)){
            $this->Version = $config['baofu_version'];
            $this->Member_Id = $config['baofu_member_Id'];
            $this->Terminal_Id = $config['baofu_terminal_Id'];
            $this->KEY_PWD = $config['baofu_key_pwd'];
            $this->PFX_FILE_PATH = ROOT_PATH.'/public/'.$config['baofu_pfx'];
            $this->CER_FILE_PATH = ROOT_PATH.'/public/'.$config['baofu_cer'];
            $this->POST_URL = $config['baofu_url'];
            $this->AesKey = $config['baofu_AesKey'];
        }

        $this->GLOBALS = [
            'Version' => $this->Version,
            'Member_Id' => $this->Member_Id,
            'Terminal_Id' => $this->Terminal_Id,
            'KEY_PWD' => $this->KEY_PWD,
            'PFX_FILE_PATH' => $this->PFX_FILE_PATH,
            'CER_FILE_PATH' => $this->CER_FILE_PATH,
            'POST_URL' => $this->POST_URL,
        ];
    }

    public function dgtl_envlp(){
        try {
            $dgtl_envlp = "01|" . $this->AesKey;//使用接收方的公钥加密后的对称密钥，并做Base64转码，明文01|对称密钥，01代表AES[密码商户自定义]
            return RSAUtil::encryptByCERFile($dgtl_envlp, $this->GLOBALS["CER_FILE_PATH"]);//公钥加密
        }catch (Exception $exception){
            Log::LogWirte('error-'.$exception->getMessage());//记录日志
        }
    }

    public function getDateAry($arr = []){
        $DateArry = array();
        $DateArry['msg_id'] = $this->getMsgID();
        $DateArry["send_time"] = Tools::getTime();
        $DateArry["version"] = $this->GLOBALS["Version"];
        $DateArry["terminal_id"] = $this->GLOBALS["Terminal_Id"];
        $DateArry["member_id"] = $this->GLOBALS["Member_Id"];
        $DateArry['msg_id'] = $this->getMsgID();
        return $DateArry;
    }

    public function getMsgID(){
        return "TISN" . Tools::getTransid() . Tools::getRand4();
    }

    //商户订单号
    public function getTransID(){
        return "TID" . Tools::getTransid() . Tools::getRand4();
    }

    //退款流水号
    public function getTransSerialNo(){
        return "RTSN" . Tools::getTransid() . Tools::getRand4();
    }

    public function getDateArry(){

        $dgtl_envlp = $this->dgtl_envlp();

        $DateArry = array();
        $DateArry["send_time"] = Tools::getTime();
        $DateArry["msg_id"] = "TISN" . Tools::getTransid() . Tools::getRand4();//报文流水号
        $DateArry["version"] = $this->GLOBALS["Version"];
        $DateArry["terminal_id"] = $this->GLOBALS["Terminal_Id"];
        $DateArry["member_id"] = $this->GLOBALS["Member_Id"];
        $DateArry["dgtl_envlp"] = $dgtl_envlp;

        return $DateArry;
    }

    /**
     * 直接支付接口
     * @param $ProtocolNo 签约协议号
     * @param $user_id 用户id
     * @param $txn_amt 支付金额, 分
     * @param $RiskItem 风控参数
     * @return void
     * @throws \think\Exception
     */
    public function singlePay($data = [])
    {
        Log::LogWirte('开始支付');//记录日志
        \think\Log::write('开始支付');

        $ReturnUrl = "";//异步通知地址。

        $DateArry = $this->getDateAry();
        $DateArry["send_time"] = Tools::getTime();
        $DateArry["txn_type"] = "08";//交易类型
        $DateArry["dgtl_envlp"] = $this->dgtl_envlp();
        $DateArry["card_info"] = "";//卡信息: 【信用卡：信用卡有效期|安全码,借记卡：传空】
        $DateArry["return_url"]=$ReturnUrl;//最多填写三个地址,不同地址用间使用‘|’分隔
        $DateArry = array_merge($DateArry,$data);

        $ProtocolNoAES = AESUtil::AesEncrypt(base64_encode($data['protocol_no']), $this->AesKey);

        $DateArry["protocol_no"]=$ProtocolNoAES;//签约协议号（密文）

        $SignVStr =  Tools::SortAndOutString($DateArry);//签名字段格式化
        $SHA1Sign = SHA1Util::Sha1AndHex(urldecode($SignVStr));//签名(注意此处urldecode方法主要是去除send_time中间的空格和符号的自动自urlencode)

        $Sign = SignatureUtils::Sign($SHA1Sign, $this->GLOBALS["PFX_FILE_PATH"],$this->GLOBALS["KEY_PWD"]);
        $DateArry["signature"]=$Sign;//签名域

        Log::LogWirte('直接支付-格式化数据' . json_encode($DateArry, JSON_UNESCAPED_UNICODE));//记录日志
        $PostString = $this->Post($DateArry, $this->GLOBALS["POST_URL"]);
        Log::LogWirte('支付返回数据：' . $PostString);//记录日志
        
        if($PostString){
            parse_str($PostString, $ReturnData);//参数解析

            if(isset($ReturnData["signature"])){
                $RSign = $ReturnData["signature"];//存储返回签名做后续验签使用。
                $RSignArray = Tools::array_remove($ReturnData, "signature");//需要删除签名字段

                $RSignVStr = Tools::SortAndOutString($RSignArray);
                $RSignature = SHA1Util::Sha1AndHex(urldecode($RSignVStr));

                if (SignatureUtils::VerifySign($RSignature, $this->GLOBALS["CER_FILE_PATH"], $RSign)) {

                    if (isset($RSignArray['resp_code'])) {
                        if($RSignArray["resp_code"] == "S"){
                            return ['code' => 200,'data' => $DateArry,'notify' => $RSignArray];
                        }elseif($RSignArray["resp_code"] == "I"){
                            return ['code' => 201,'data' => $DateArry,'notify' => $RSignArray];
                        }
                    }
                }
                return ['code' => 0,'notify' => $RSignArray];
            }
        }
        return ['code' => 0,'notify' => ''];
    }

    public function queryPay($data = []){

        Log::LogWirte('查询支付');//记录日志
        \think\Log::write('查询支付');

        $DateArry = $this->getDateArry();
        $DateArry["txn_type"]= "07";//交易类型
        $DateArry["orig_trade_date"]= Tools::getTime();//
        $DateArry["orig_trans_id"]=$data['trans_id'];//交易时的trans_id


        $SignVStr =  Tools::SortAndOutString($DateArry);//签名字段格式化
        $SHA1Sign = SHA1Util::Sha1AndHex(urldecode($SignVStr));//签名(注意此处urldecode方法主要是去除send_time中间的空格和符号的自动自urlencode)

        $Sign = SignatureUtils::Sign($SHA1Sign, $this->GLOBALS["PFX_FILE_PATH"],$this->GLOBALS["KEY_PWD"]);
        $DateArry["signature"]=$Sign;//签名域

        $PostString  =  HttpClient::Post($DateArry, $this->GLOBALS["POST_URL"]);

        if(!empty($PostString)){
            parse_str($PostString,$ReturnData);//参数解析

            if(array_key_exists("signature",$ReturnData)){
                $RSign=$ReturnData["signature"];//存储返回签名做后续验签使用。
                $RSignArray = Tools::array_remove($ReturnData, "signature");//需要删除签名字段
                $RSignVStr =Tools::SortAndOutString($RSignArray);

                //签名(注意此处urldecode方法主要是去除send_time中间的空格和符号的自动自urlencode)
                $RSignature = SHA1Util::Sha1AndHex(urldecode($RSignVStr));

                if(SignatureUtils::VerifySign($RSignature,$this->GLOBALS["CER_FILE_PATH"],$RSign)){

                    Log::LogWirte('直接支付-格式化数据'.json_encode($RSignArray,JSON_UNESCAPED_UNICODE ));//记录日志
                    \think\Log::write('直接支付-格式化数据'.json_encode($RSignArray,JSON_UNESCAPED_UNICODE ));

                    if(array_key_exists("resp_code",$RSignArray)){
                        if($RSignArray["resp_code"] == "S"){
                            return ['code' => 200,'notify' => $RSignArray];
                        }else if($RSignArray["resp_code"] == "I"){
                            return ['code' => 201,'notify' => $RSignArray];
                        }else if($RSignArray["resp_code"] =="F"){
                            return ['code' => 0,'notify' => $RSignArray];
                        }
                    }
                }
            }
        }
        Log::LogWirte('查询支付结束-'.$PostString);//记录日志
        return ['code' => 0,'notify' => $PostString];
    }

    public function Post($PostArry,$Req_Url){
        try {
            $postData = $PostArry;
            $postDataString = http_build_query($postData);//格式化参数

            Log::LogWirte('发送参数-'.$postDataString);//记录日志
            \think\Log::write('请求参数-'.$postDataString);

            $curl = curl_init(); // 启动一个CURL会话
            curl_setopt($curl, CURLOPT_URL, $Req_Url); // 要访问的地址
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); // 对认证证书来源的检查
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); // 从证书中检查SSL加密算法是否存在
            //curl_setopt($curl, CURLOPT_SSLVERSION, 6); //CURL_SSLVERSION_DEFAULT (0), CURL_SSLVERSION_TLSv1 (1), CURL_SSLVERSION_SSLv2 (2), CURL_SSLVERSION_SSLv3 (3), CURL_SSLVERSION_TLSv1_0 (4), CURL_SSLVERSION_TLSv1_1 (5)， CURL_SSLVERSION_TLSv1_2 (6) 中的其中一个。
            curl_setopt($curl, CURLOPT_POST, true); //发送一个常规的Post请求
            curl_setopt($curl, CURLOPT_POSTFIELDS, $postDataString); // Post提交的数据包
            curl_setopt($curl, CURLOPT_TIMEOUT, 60); // 设置超时限制防止死循环返回
            curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
            $tmpInfo = curl_exec($curl); // 执行操作
            if (curl_errno($curl)) {
                $tmpInfo = curl_error($curl);//捕抓异常
            }
            curl_close($curl); // 关闭CURL会话

            \think\Log::write('返回参数-'.$tmpInfo);
            Log::LogWirte('返回参数-'.$tmpInfo);//记录日志

            return $tmpInfo; // 返回数据
        } catch (Exception $ex) {
            echo $ex->getTraceAsString();
        }
    }
}